﻿using System;
using Microsoft.Xna.Framework;
using XnaPlus.Common.Extensions;

namespace FlipRunner.Physics
{
    /// <summary>
    /// Velocity Vector in Meters Per Second in a 2D Cartesian plane
    /// </summary>
    public struct CartesianVector: ISize, IEquatable<CartesianVector>
    {

        ///<summary>
        /// Horizontal value in Meters
        /// </summary>
        public readonly float X;

        /// <summary>
        /// Vertical value in Meters
        /// </summary>
        public readonly float Y;

        public static readonly CartesianVector Zero = new CartesianVector();
        public static readonly CartesianVector One = new CartesianVector(1,1);
        public static readonly CartesianVector UnitX = new CartesianVector(1,0);
        public static readonly CartesianVector UnitY = new CartesianVector(0,1);
       

        public Vector2 ToPixels(float pixelsPerMeter)
        {
            return new Vector2(pixelsPerMeter/X, -pixelsPerMeter/Y);
        }

        public CartesianVector(float x, float y) : this()
        {
            X = x;
            Y = y;
        }

        public Point GetPixelOffset(TimeSpan timeDelta, float pixelsPerMeter)
        {
            return (ToPixels(pixelsPerMeter)*(float)timeDelta.TotalSeconds).Round();
        }

        public static CartesianVector operator + (CartesianVector velocity1, CartesianVector velocity2)
        {
            return new CartesianVector(velocity1.X + velocity2.X, velocity1.Y + velocity2.Y);
        }

        public static CartesianVector operator -(CartesianVector velocity1, CartesianVector velocity2)
        {
            return new CartesianVector(velocity1.X - velocity2.X, velocity1.Y - velocity2.Y);
        }

        public float DotProduct(CartesianVector other)
        {
            return X*other.X + Y * other.Y;
        }

        public static bool operator ==(CartesianVector vector1, CartesianVector vector2)
        {
            return vector1.Equals(vector2);
        }

        public static CartesianVector operator -(CartesianVector vector)
        {
            return new CartesianVector(-vector.X, -vector.Y);
        }

        public static bool operator !=(CartesianVector vector1, CartesianVector vector2)
        {
            return !(vector1 == vector2);
        }

        public static CartesianVector operator *(CartesianVector velocity, float scalar)
        {
            return new CartesianVector(velocity.X * scalar, velocity.Y * scalar);
        }

        public static CartesianVector operator *(float scalar, CartesianVector velocity)
        {
            return new CartesianVector(velocity.X * scalar, velocity.Y * scalar);
        }

        public static CartesianVector operator /(CartesianVector velocity, float scalar)
        {
            return new CartesianVector(velocity.X / scalar, velocity.Y / scalar);
        }

        public static explicit operator Vector2(CartesianVector velocity)
        {
            return new Vector2(velocity.X, velocity.Y);
        }

        public static explicit operator CartesianVector(Vector2 velocity)
        {
            return new CartesianVector(velocity.X, velocity.Y);
        }

        public override string ToString()
        {
            return ((Vector2) this).ToString();
        }

        public bool Equals(CartesianVector other)
        {
            return X.Equals(other.X) && Y.Equals(other.Y);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj is CartesianVector && Equals((CartesianVector) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (X.GetHashCode()*397) ^ Y.GetHashCode();
            }
        }

        float ISize.Width { get { return X; } }
        float ISize.Height { get { return Y; } }
    }
}